package demo3

import (
	"fmt"
	"time"
)

// TestDemo312 内存缓存 来提升性能, 避免重复计算
func TestDemo312() {
	// demo1: 生成斐波那契数列, 普通的计算方法1
	test3121()
	// demo2: 普通的计算方法2
	test3122()
	// demo3: 内存缓存方法
	test3123()
}

// 返回值 res 赋值，返回
func fibonacci1(n int) (res int) {
	if n <= 1 {
		res = 1
	} else {
		res = fibonacci1(n-1) + fibonacci1(n-2)
	}
	return
}

// 普通的计算方法1
func test3121() {
	start := time.Now()
	result := 0
	for i := 0; i <= 40; i++ {
		result = fibonacci1(i)
		fmt.Printf("fibonacci11(%d) is %d\n", i, result)
	}
	end := time.Now()
	delta := end.Sub(start)
	fmt.Printf("fibonacci1 took time %s\n", delta)
}

// 斐波那契数列
func fibonacci2(n int) int {
	if n < 2 {
		return n
	}
	return fibonacci2(n-2) + fibonacci2(n-1)
}

// 普通的计算方法2
func test3122() {
	start := time.Now()
	result := 0
	for i := 0; i <= 40; i++ {
		result = fibonacci2(i)
		fmt.Printf("fibonacci22(%d) is %d\n", i, result)
	}
	end := time.Now()
	delta := end.Sub(start)
	fmt.Printf("fibonacci2 took time %s\n", delta)
}

// LIM 内存缓存的方法
const LIM = 41

// 数组
var fibs [LIM]uint64

func test3123() {
	var result uint64
	start := time.Now()
	for i := 0; i < LIM; i++ {
		result = fibonacii3(i)
		fmt.Printf("fibonacci22(%d) is %d\n", i, result)
	}
	end := time.Now()
	delta := end.Sub(start)
	fmt.Printf("fibonacci3 took time %s\n", delta)
}

func fibonacii3(n int) (res uint64) {
	// 记忆化：检查数组中是否已知 斐波那契 (n)
	if fibs[n] != 0 {
		res = fibs[n]
		return
	}

	if n <= 1 {
		res = 1
	} else {
		res = fibonacii3(n-1) + fibonacii3(n-2)
	}

	fibs[n] = res
	return
}

// tips: 内存缓存的技术在使用计算成本相对昂贵的函数时非常有用（不仅限于例子中的递归），
//		譬如大量进行相同参数的运算。这种技术还可以应用于纯函数中，即相同输入必定获得相同输出的函数
